package org.chnxi.study.concurrent.abc.demo;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 使用ReentrantLock + Condition实现
 */
public class Demo1 {

    public static void main(String[] args) {
        LockABC abc = new LockABC();

        new Thread(()->{
            try {
                TimeUnit.MILLISECONDS.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            abc.printA();
        } , "T-A").start();

        new Thread(()->{
            abc.printB();
        } , "T-B").start();

        new Thread(()->{
            abc.printC();
        } , "T-C").start();
    }

    public static class LockABC{
        private static ReentrantLock lock = new ReentrantLock();
        private static Condition c1 = lock.newCondition();
        private static Condition c2 = lock.newCondition();
        private static Condition c3 = lock.newCondition();

        // 0 -> run printA
        // 1 -> run printB
        // 2 -> run printC
        private static int flag = 0;

        public void printA(){
            lock.lock();
            System.out.println(Thread.currentThread().getName()+" printA is locked");
            try{
                TimeUnit.MILLISECONDS.sleep(100);
                while (flag != 0){
                    c1.await();
                }
                System.out.println(Thread.currentThread().getName()+":A");
                flag = 1;
                c2.signal();
            }catch (Exception e){
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName()+" printA  unlocke");
                lock.unlock();
            }
        }

        public void printB(){
            lock.lock();

            System.out.println(Thread.currentThread().getName()+" printB is locked");
            try{
                TimeUnit.MILLISECONDS.sleep(100);
                while (flag != 1){
                    c2.await();
                }
                System.out.println(Thread.currentThread().getName()+":B");
                flag = 2;
                c3.signal();
            }catch (Exception e){
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName()+" printB  unlocke");
                lock.unlock();
            }
        }

        public void printC(){
            lock.lock();

            System.out.println(Thread.currentThread().getName()+" printC is locked");
            try{
                TimeUnit.MILLISECONDS.sleep(100);
                while (flag != 2){
                    c3.await();
                }
                System.out.println(Thread.currentThread().getName()+":C");
                flag = 0;
                c1.signal();
            }catch (Exception e){
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName()+" printC  unlocke");
                lock.unlock();
            }
        }
    }

}
